//
//  TimerProxy.swift
//  TTCOM
//
//  Created by Toj on 6/16/22.
//

import UIKit

/** Timer 消息中心
 * 避免Timer引起的循环引用问题
 */
open class TimerProxy: NSObject {
    
    private weak var _target: NSObjectProtocol?
    private var _selector: Selector
    
    // 外界传进来的
    public weak var timer: Timer?
    
    public required init(target: NSObjectProtocol, selector: Selector) {
        _target = target
        _selector = selector
        
        super.init()

        // 对象是否能响应方法
        guard target.responds(to: selector) else { return }
        
        // 方法重定向, 如果当前对象为nil代表已被释放, 直接释放timer
        let name = #selector(TimerProxy.forwardingMethod)
        guard let method = class_getInstanceMethod(classForCoder, name) else { return }
        
        let imp = method_getImplementation(method)
        let type = method_getTypeEncoding(method)
        class_replaceMethod(classForCoder, selector, imp, type)
    }
    
    @objc private func forwardingMethod() {
        // 如果target未被释放，则调⽤target⽅法，否则释放timer
        if _target != nil {
            _target?.perform(_selector)
            return
        }
        // print("TimerProxy: callBack selector")
        timer?.invalidate()
        timer = nil
    }
    
    deinit {
        print("-->toj: class:\(st_className), func: \(#function)")
    }
}

public extension Timer {
    
    convenience init(_ timeInterval: TimeInterval, target aTarget: NSObjectProtocol, selector aSelector: Selector, userInfo: Any? = nil, repeats yesOrNo: Bool = true) {
        let proxy = TimerProxy(target: aTarget, selector: aSelector)
        self.init(timeInterval: timeInterval, target: proxy, selector: aSelector, userInfo: userInfo, repeats: yesOrNo)
        proxy.timer = self
        RunLoop.current.add(self, forMode: .common)
    }
    
    class func st_scheduledTimer(timeInterval aInterval: TimeInterval, target aTarget: NSObjectProtocol, selector aSelector: Selector, userInfo: Any? = nil, repeats yesOrNo: Bool = true) -> Timer {
        
        let proxy = TimerProxy(target: aTarget, selector: aSelector)
        let timer = Timer.scheduledTimer(timeInterval: aInterval, target: proxy, selector: aSelector, userInfo:userInfo, repeats: yesOrNo)
        proxy.timer = timer
        RunLoop.current.add(timer, forMode: .common)
        
        return timer
    }
}
